﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using MiniFox.Infrastructure;
using MiniFox.Platform.Applications.Auth;
using MiniFox.Platform.Resources;
using MiniFox.Web;
using System.Security.Claims;

namespace MiniFox.Platform.Applications.Web.Filters
{
    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public abstract class AuthorizationFilter : Attribute, IAuthorizationFilter, IAsyncAuthorizationFilter
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        protected abstract AuthorizationClient CreateAuthClient(HttpContext httpContext);
        /// <summary>
        /// 
        /// </summary>
        public string[] Roles
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        public Task OnAuthorizationAsync(AuthorizationFilterContext filterContext)
        {
            try
            {
                OnAuthorization(filterContext);
            }
            catch (Exception exception)
            {
                return Task.FromException(exception);
            }

            return Task.CompletedTask;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="filterContext"></param>
        public void OnAuthorization(AuthorizationFilterContext filterContext)
        {
            if (AnonymousAccessiable(filterContext))
            {
                return;
            }
            if (!IsAuthorized(filterContext))
            {
                HandleUnauthorizedRequest(filterContext);
            }
        }
        /// <summary>
        /// 授权检查
        /// </summary>
        /// <param name="filterContext"></param>
        /// <returns></returns>
        protected virtual bool IsAuthorized(AuthorizationFilterContext filterContext)
        {
            var request = filterContext.HttpContext.Request;
            var response = filterContext.HttpContext.Response;
            
            //获取当前url
            string requestUrl = request.GetFullAbsolutionPath();
            var authClient = this.CreateAuthClient(filterContext.HttpContext);
            //例外url检查，无需授权
            if (authClient.IsExceptionUrl(request.Path))
            {
                return true;
            }
            if (!authClient.VerifyTokenState())//验证本地token
            {
                return false;
            }

            ClaimsPrincipal principal = authClient.Principal;
            if (principal == null || principal.Identity == null || !principal.Identity.IsAuthenticated)
            {
                return false;
            }
            //将身份设置到当前上下文中
            filterContext.HttpContext.User = principal;

            filterContext.HttpContext.SetAuthClient(authClient);

            if (PublicAccessiable(filterContext))
            {
                return true;
            }
            if (filterContext.HttpContext.Request.IsAjaxRequest()) //ajax请求响应判断是否为前后端分离
            {
                //前后端分离模式检查角色
                this.Roles = authClient.GetRoles(filterContext.HttpContext.Request.Headers.Referer, requestUrl);
            }
            else
            {
                //一体模式检查角色
                this.Roles = authClient.GetRoles(requestUrl);
            }
            if (Roles.Length > 0 && !Roles.Any(principal.IsInRole))
            {
                return false;
            }

            return true;
        }
        /// <summary>
        /// 未经授权时的响应
        /// </summary>
        /// <param name="filterContext"></param>
        protected virtual void HandleUnauthorizedRequest(AuthorizationFilterContext filterContext)
        {
            filterContext.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
            filterContext.Result = new JsonResult(new Response
            {
                Code = ResErrorCode.ERR_Unauthorized,
                Message = ResMessage.ERR_Unauthorized
            });
        }
        //允许匿名访问时，自动跳过鉴权
        private static bool AnonymousAccessiable(AuthorizationFilterContext filterContext)
        {
            //可匿名访问action或controller
            var authorizeAttributes = filterContext.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>();
            return authorizeAttributes.Any();
        }

        //允许公开访问时，自动跳过鉴权
        private static bool PublicAccessiable(AuthorizationFilterContext filterContext)
        {
            //可公开访问action或controller
            var authorizeAttributes = filterContext.ActionDescriptor.EndpointMetadata.OfType<PublicAccessibleAttribute>();
            return authorizeAttributes.Any();
        }

    }
}
